
import { _decorator, Component, Node, Prefab, instantiate, NodePool, director, JsonAsset, UITransform, v2, view } from 'cc';
import { eventDispatcher, PREFAB_MAP, SCENE_NAME, TILE_HEIGHT, TILE_WIDTH } from '../Constants';
import { Entity, IEntity } from '../entity/Entity';
import { Smoke } from '../entity/Smoke';
import { Direction } from '../enums/Direction';
import { EventType } from '../enums/EventType';
import { DataManager } from '../manager/DataManager';
import { TileMap } from '../tile/TileMap';
import { CocosUtils } from '../utils/CocosUtils';
const { ccclass, property } = _decorator;


@ccclass('BattleManager')
export class BattleManager extends Component {

    private _stage: Node;
    private _tileMap: Node;
    private _smokePool = new NodePool();

    public onEnable(): void {
        eventDispatcher.on(EventType.NEXT_LEVEL, this.nextLevel, this);
        eventDispatcher.on(EventType.CREATE_SMOKE, this.craeteSmoke, this);
        eventDispatcher.on(EventType.RECYLE_SMOKE, this.recyleSmoke, this);
        eventDispatcher.on(EventType.MENU_SELECT, this.onMenuSelected, this);
        eventDispatcher.on(EventType.SAVE_RECORD, this.saveRecord, this);
        eventDispatcher.on(EventType.COMPLETE, this.onLevelComplete, this);
    }

    public onDisable(): void {
        eventDispatcher.targetOff(this);
    }

    public start(): void {
        this._stage = this.node.getChildByName("Stage");

        DataManager.instance.init();
        this.initLevel();
    }

    private initLevel(): void {
        DataManager.instance.reset();

        const mapInfo = DataManager.instance.currentLevel.mapInfo;
        if (mapInfo) {
            this.gennerateTileMap();
            this.generateEntity();
            this.adjustStagePosition();
        }
    }

    private nextLevel(): void {
        this._stage.destroyAllChildren();
        DataManager.instance.nextLevel();
        this.initLevel();
    }

    private gennerateTileMap(): void {
        this._tileMap = new Node();
        const transform = this._tileMap.addComponent(UITransform);
        transform.setAnchorPoint(v2(0, 1));
        this._stage.addChild(this._tileMap);

        const tileMapManager = this._tileMap.addComponent(TileMap);
        tileMapManager.init(DataManager.instance.currentLevel.mapInfo);
    }

    private generateEntity(): void {
        const entitiesData = DataManager.instance.currentLevel.entities.sort((a, b) => a.type === Entity.Type.PLAYER ? 1 : -1);
        for (const data of entitiesData) {
            const prefabPath: string = PREFAB_MAP[data.type];
            if (!prefabPath) {
                continue;
            }
            const prefab = CocosUtils.getAsset(prefabPath, Prefab);
            const node = instantiate(prefab);
            this._stage.addChild(node);
            const entity = node.getComponent(Entity);
            entity.init(data);
            DataManager.instance.addEntity(entity);
        }
    }

    private adjustStagePosition(): void {
        const { row, column } = DataManager.instance.currentLevel.mapInfo;
        const offsetX = (column * TILE_WIDTH) / 2;
        const offsetY = row * TILE_HEIGHT / 2 + 80;
        this._stage.setPosition(-offsetX, offsetY);
    }

    private craeteSmoke(x: number, y: number, direction: Direction): void {
        let node = this._smokePool.get();
        if (!node) {
            const smokePrefab = CocosUtils.getAsset(PREFAB_MAP[Entity.Type.SMOKE], Prefab);
            node = instantiate(smokePrefab);
        }
        this._stage.insertChild(node, this._stage.children.length - 1);
        const smoke = node.getComponent(Smoke);
        smoke.init({
            x,
            y,
            direction,
            state: Entity.State.IDLE,
            type: Entity.Type.SMOKE
        });
    }

    private recyleSmoke(node: Node): void {
        node && this._smokePool.put(node);
    }

    public saveRecord(): void {
        const item = DataManager.instance.entities.map(entity => entity.getData());
        DataManager.instance.records.push(item);
    }

    public rollbackRecord(): void {
        const record = DataManager.instance.records.pop();
        if (record) {
            for (const data of record) {
                for (const entity of DataManager.instance.entities) {
                    if (data.id === entity.id) {
                        entity.setData(data);
                        break;
                    }
                }
            }
        }
    }

    private restart(): void {
        const record = DataManager.instance.records.shift();
        if (record) {
            for (const data of record) {
                for (const entity of DataManager.instance.entities) {
                    if (data.id === entity.id) {
                        entity.setData(data);
                        break;
                    }
                }
            }
            DataManager.instance.records = [];
        }
        eventDispatcher.emit(EventType.LOAD_SCENE_FINISH);
    }

    private async onMenuSelected(type: number): Promise<void> {
        if (type === 0) {
            this.rollbackRecord();
        } else if (type === 1) {
            this.restart();
        } else if (type === 2) {
            await CocosUtils.loadScene(SCENE_NAME.START);
        }
    }

    private onLevelComplete(doorId: number): void {
        this.nextLevel();
    }
}